package ch.mylonas.saometer.data.processing;

import ch.mylonas.saometer.config.SaoMeterConfig;
import ch.mylonas.saometer.data.SerialData;

public class PunchDetectionImpl implements PunchDetection {
	
	SaoMeterConfig saoMeterConfig;
	int threshold;
	int duration;
	float gFactor;
	int minAccDuration;
	int showBefore;
	
	boolean punchStarted = false;
	
	public PunchDetectionImpl() {
		super();
	}

	@Override
	public Punch detectPunch(SerialData serialData) {
		
		Punch punch = null;
		int[] data = serialData.getData(0);
		
		if(punchStarted){
			if(!serialData.isRunning()){
				this.punchStarted = false;
				punch = this.computePunch(data);
				serialData.isRunning(true);
			}
		}else{
			if(data[data.length-1] <= threshold){
				this.punchStarted = true;
				serialData.startCountdown(this.duration);
			}
		}
		
		return punch;
	}
	
	
	protected Punch computePunch(int[] data){
		
		float sumAcc = 0;
		float maxAcc = 0;
		
		int[] dataPart = new int[this.duration + this.showBefore];
		
		// get the maximum and sum of acceleration
		int k=0;
		// consider data a bit before the is reached
		int start = data.length-this.duration - this.showBefore;
		int aboveThreshold = 0;
		boolean punchDetected = false;
		
		for(int i=start; i<data.length; i++){
			int point = data[i];
			dataPart[k++] = point;
			
			// because my accelerometer is reversed, otherwise it would be: point - zeroAxis
			int correctedPoint = this.saoMeterConfig.getZeroAxis() - point;
			
			if(correctedPoint > 0 && !punchDetected){
				float acc = correctedPoint * this.gFactor;
				if(acc > maxAcc){
					maxAcc = acc;
				}
				sumAcc += acc;
				aboveThreshold++;
			}else{
				if(aboveThreshold >= this.minAccDuration){
					punchDetected = true;
				}
			}
			
		}
		
		Punch punch = new Punch();
		punch.setAcceleration(sumAcc);
		punch.setMaxAcceleration(maxAcc);
		punch.setData(dataPart);
		
		return punch;
	}
	
	
	public int getThreshold() {
		return threshold;
	}

	public void setThreshold(int threshold) {
		this.threshold = threshold;
	}

	public int getDuration() {
		return duration;
	}

	public void setDuration(int duration) {
		this.duration = duration;
	}

	public float getgFactor() {
		return gFactor;
	}

	public void setgFactor(float gFactor) {
		this.gFactor = gFactor;
	}

	public SaoMeterConfig getSaoMeterConfig() {
		return saoMeterConfig;
	}

	public void setSaoMeterConfig(SaoMeterConfig saoMeterConfig) {
		this.saoMeterConfig = saoMeterConfig;
	}

	public int getMinAccDuration() {
		return minAccDuration;
	}

	public void setMinAccDuration(int minAccDuration) {
		this.minAccDuration = minAccDuration;
	}

	public int getShowBefore() {
		return showBefore;
	}

	public void setShowBefore(int showBefore) {
		this.showBefore = showBefore;
	}

	
	
	
}
